package admm;

import weka.core.matrix.Matrix;

public class ADMMForLinearPrograming
{
	private Matrix A;
	private Matrix u;
	private Matrix C;
	private double rho = 0.00001;
	private Matrix x;
	private double errorR = 1e-1;
	private int maxIter = 100000;
	private Matrix z;
	private Matrix b;

	public ADMMForLinearPrograming(Matrix x, Matrix A, Matrix K, Matrix u,
			Matrix C, double rho)
	{
		this.A = A;
		this.u = u;
		this.C = C;
		this.rho = rho;
		this.x = x;
	}

	public void run()
	{

		// //update x
		double arrayM1[][] = new double[this.A.getArray().length
				+ this.A.getArray()[0].length][this.A.getArray().length
				+ this.A.getArray()[0].length];
		double arrayA[][] = this.A.getArray();
		double arrayA2[][] = this.A.transpose().getArray();

		for (int j = 0; j < arrayM1.length; j++)
		{
			for (int e = 0; e < arrayM1.length; e++)
			{
				if (j < arrayA.length && e < arrayA.length)
				{
					if (j == e)
					{
						arrayM1[j][e] = 1;
					}
				}
				if (j < arrayA.length && e >= arrayA.length)
				{
					arrayM1[j][e] = arrayA2[j][e - arrayA.length];
				}
				if (j >= arrayA.length && e < arrayA.length)
				{
					arrayM1[j][e] = arrayA[j - arrayA.length][e];
				}
			}
		}

		Matrix m1 = new Matrix(arrayM1);

		m1 = m1.inverse();
		double[][] arrayB = this.b.getArray();
		for (int i = 0; i < this.maxIter; i++)
		{

			// ///////////update x
			Matrix zu = this.z.minus(this.u).times(this.rho).minus(this.C);
			double[][] arrayZU = zu.getArray();
			double arrayZUB[][] = new double[this.z.getArray().length
					+ this.b.getArray().length][1];
			Matrix zub = null;
			for (int j = 0; j < arrayZUB.length; j++)
			{
				if (j < arrayZU.length)
				{
					arrayZUB[j][0] = arrayZU[j][0];
				}
				else
				{
					arrayZUB[j][0] = arrayB[j - arrayZU.length][0];
				}
				zub = new Matrix(arrayZUB);
			}
			Matrix result = m1.times(zub);
			double[][] arrayResult = result.getArray();
			double[][] arrayX = new double[this.x.getArray().length][1];
			for (int j = 0; j < arrayX.length; j++)
			{
				arrayX[j][0] = arrayResult[j][0];
			}

			this.x = new Matrix(arrayX);

			// //////////////////////////update z
			Matrix z2 = this.x.plus(this.u);
			double[][] arrayZ2 = z2.getArray();
			for (int j = 0; j < arrayZ2.length; j++)
			{
				if (arrayZ2[j][0] < 0)
				{
					arrayZ2[j][0] = 0;
				}

				this.z = new Matrix(arrayZ2);
			}
			// //////////////update u

			this.u = this.u.plus(this.x).minus(this.z);

			// //////////////compute r s
			
			Matrix mr=this.A.times(this.x).minus(this.C);
			double r=Math.sqrt(mr.norm2());
		}

	}

	public static void main(String args[])
	{
		double[][] x =
		{
		{ 0 },
		{ 0 },
		{ 0 } };
		double[][] A =
		{
		{ 2, 300, 1 },
		{ 1, 1, 1 } };
		double K[][] =
		{
		{ 1 },
		{ 1 },
		{ 1 } };
		double u[][] =
		{
		{ 0 },
		{ 0 } };
		double C[][] =
		{
		{ 6 },
		{ 3 } };
		double rho = 0.001;
		ADMMForLinearPrograming a = new ADMMForLinearPrograming(new Matrix(x),
				new Matrix(A), new Matrix(K), new Matrix(u), new Matrix(C), rho);
		a.run();
	}

	public Matrix getX()
	{
		return x;
	}

	public void setX(Matrix x)
	{
		this.x = x;
	}

	public double getErrorR()
	{
		return errorR;
	}

	public void setErrorR(double errorR)
	{
		this.errorR = errorR;
	}

	public int getMaxIter()
	{
		return maxIter;
	}

	public void setMaxIter(int maxIter)
	{
		this.maxIter = maxIter;
	}

	public Matrix getA()
	{
		return A;
	}

	public void setA(Matrix a)
	{
		A = a;
	}

	public Matrix getU()
	{
		return u;
	}

	public void setU(Matrix u)
	{
		this.u = u;
	}

	public Matrix getC()
	{
		return C;
	}

	public void setC(Matrix c)
	{
		C = c;
	}

	public double getRho()
	{
		return rho;
	}

	public void setRho(double rho)
	{
		this.rho = rho;
	}

}
